﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;

namespace SDL
{
    using TabViewList = ObservableList<TabView>;

    // A view container in which headers are displayed as a list of strings, images,
    // or both, depending on space and user selection. The group has a standard
    // view, or it can be collapsed to save space.
    // In standard view, one element is always required to be active. The header
    // list is displayed horizontally, with a fixed panel below which displays the
    // content of the active item.
    // In the collapsed view, the header list can be displayed either horizontally
    // or vertically. When an item is selected, it's content is opened in a floating
    // panel which will close when it loses focus.
    [ContentProperty("Items")]
    public class TabGroup : Control, IDockElement, IViewContainer
    {
        /////////////////////////////////////////////////////////////////////////////
        // Public Constructor

        public TabGroup()
        {
            Items = new TabViewList();

            TextBox textBox = new TextBox();
            textBox.MinWidth = 120;
            textBox.MinHeight = 120;
            textBox.Text = "Content";
            textBox.HorizontalAlignment = HorizontalAlignment.Stretch;
            textBox.VerticalAlignment = VerticalAlignment.Stretch;
            textBox.HorizontalContentAlignment = HorizontalAlignment.Center;
            textBox.VerticalContentAlignment = VerticalAlignment.Center;
            Content = textBox;

            Loaded += new RoutedEventHandler(TabGroup_Loaded);
            Unloaded += new RoutedEventHandler(TabGroup_Unloaded);
        }

        public TabViewList Items
        {
            get { return (TabViewList)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }

        public static DependencyProperty ItemsProperty = DependencyProperty.RegisterAttached("Items", typeof(TabViewList), typeof(TabGroup), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

        public object Content
        {
            get { return (object)GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }

        public static DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(Object), typeof(TabGroup));

        /////////////////////////////////////////////////////////////////////////////
        // IElement

        public FrameworkElement AsFrameworkElement()
        {
            return this;
        }

        /////////////////////////////////////////////////////////////////////////////
        // IDockElement

        public Orientation Orientation { get; private set; }

        public void UpdateOrientation()
        {
            // find the desired orientation
            Orientation desiredOrientation;
            IDockElement parent = Parent as IDockElement;
            if( parent != null )
            {
                // if parent is an element, the orientation is inverse
                switch( parent.Orientation )
                {
                case Orientation.Horizontal:
                    desiredOrientation = Orientation.Vertical;
                    break;
                case Orientation.Vertical:
                default:
                    desiredOrientation = Orientation.Horizontal;
                    break;
                }
            }
            else
            {
                // if parent is not an element, it is the frame
                switch( DockManager.GetEdge(this) )
                {
                case Edge.Left:
                case Edge.Right:
                    desiredOrientation = Orientation.Vertical;
                    break;
                case Edge.Top:
                case Edge.Bottom:
                default:
                    desiredOrientation = Orientation.Horizontal;
                    break;
                }
            }

            // apply the desired orientation
            if( desiredOrientation != Orientation )
            {
                Orientation = desiredOrientation;
            }
        }

        public bool CheckDrop(IDockElement element, Point location)
        {
            //if( VisualTreeHelper.HitTest(this, PointFromScreen(location)) == null ) return false;

            //// if the drag location is inside the drag area, TODO
            //if( VisualTreeHelper.HitTest(_dragArea, _dragArea.PointFromScreen(location)) != null )
            //{
            //    Console.WriteLine("Check drop in tab group.");
            //}
            //return true;

            return false;
        }

        /////////////////////////////////////////////////////////////////////////////
        // IViewContainer

        public void StartDrag(IViewElement element)
        {
            //// if the element is the only one, the whole group is being dragged
            //if( Items.Count == 1 )
            //{
            //    // check if the container will handle the start drag
            //    if( _container.StartDrag(this) ) return;

            //    // get the offset relative to the group
            //    _offset = Mouse.GetPosition(this);
            //}
            //// otherwise, only the item is being dragged
            //else
            //{
            //    // get the offset relative to the item
            //    _offset = Mouse.GetPosition(element);
            //}

            //// save the element
            //_element = element;

            //// listen for mouse events to reorder or tear off the element
            //Mouse.Capture(this);
            //MouseMove += new MouseEventHandler(ElementDrag_Check);
            //MouseLeftButtonUp += new MouseButtonEventHandler(ElementDrag_Cancel);
        }

        /////////////////////////////////////////////////////////////////////////////
        // Event Handlers

        private void TabGroup_Loaded(object sender, EventArgs e)
        {
            _container = Parent as IDockContainer;
        }

        private void TabGroup_Unloaded(object sender, EventArgs e)
        {
            _container = null;
        }

        private void DragArea_MouseDown(object sender, MouseButtonEventArgs e)
        {
            switch( e.ClickCount )
            {
            case 1:
                DragArea_StartDrag(sender, e);
                break;
            case 2:
                DragArea_AutoSize(sender, e);
                break;
            }
        }

        private void DragArea_StartDrag(object sender, EventArgs e)
        {
            //// pass the start drag up, and return if it was handled
            //if( _container.StartDrag(this) ) return;

            //// save the current mouse position
            //_offset = Mouse.GetPosition(this);

            //// start listening for tear off
            //Mouse.Capture(this);
            //MouseMove += new MouseEventHandler(GroupDrag_Check);
            //MouseLeftButtonUp += new MouseButtonEventHandler(GroupDrag_Cancel);
        }

        private void DragArea_AutoSize(object sender, EventArgs e)
        {
            Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            _container.AutoSize(DesiredSize);
        }

        private void GroupDrag_Check(object sender, EventArgs e)
        {
            //// if the mouse has left the drag area, start the tear off
            //if( !IsMouseInDragArea() )
            //{
            //    // call the cancel event handler to stop listening for events
            //    GroupDrag_Cancel(sender, e);

            //    // start the tear off
            //    _container.TearOff(this, _offset, new Size(ActualWidth,
            //                                               ActualHeight));
            //}
        }

        private void GroupDrag_Cancel(object sender, EventArgs e)
        {
            // stop listening for tear off
            MouseMove -= new MouseEventHandler(GroupDrag_Check);
            MouseLeftButtonUp -= new MouseButtonEventHandler(GroupDrag_Cancel);
            Mouse.Capture(null);
        }

        private void ElementDrag_Check(object sender, EventArgs e)
        {
            //// if the mouse is no longer in the drag area, perform a tear off
            //if( !IsMouseInDragArea() )
            //{
            //    ElementDrag_TearOff(sender, e);
            //    return;
            //}

            //// get the mouse position
            //Point pos = Mouse.GetPosition(this);

            //// get the rectangle of the current element
            //Rect curRect = new Rect();
            //{
            //    TabView tabView = Items[SelectedIndex] as TabView;
            //    curRect.Location =
            //        tabView.TransformToAncestor(this).Transform(new Point(0, 0));
            //    curRect.Size = new Size(tabView.ActualWidth, tabView.ActualHeight);
            //}

            //// if the first element is selected, check for tearing off to the left
            //if( SelectedIndex == 0 )
            //{
            //    if( pos.X < curRect.Left )
            //    {
            //        ElementDrag_TearOff(sender, e);
            //        return;
            //    }
            //}
            //// otherwise, check for swapping to the left
            //else
            //{
            //    // get the rectangle of the previous element
            //    TabView tabView = Items[SelectedIndex - 1] as TabView;
            //    Rect prvRect = new Rect();
            //    prvRect.Location =
            //        tabView.TransformToAncestor(this).Transform(new Point(0, 0));
            //    prvRect.Size = new Size(tabView.ActualWidth, tabView.ActualHeight);

            //    // find the center of the two elements
            //    double center = (prvRect.Left + curRect.Right) / 2.0;

            //    // if the mouse is past the center, swap the two elements
            //    if( pos.X < center )
            //    {
            //        int newIndex = SelectedIndex - 1;
            //        object item = Items[SelectedIndex];
            //        Items.RemoveAt(SelectedIndex);
            //        Items.Insert(newIndex, item);
            //        SelectedIndex = newIndex;
            //    }
            //}

            //// if the last element is selected, check for tearing off to the right
            //if( SelectedIndex == Items.Count - 1 )
            //{
            //    if( pos.X > curRect.Right )
            //    {
            //        ElementDrag_TearOff(sender, e);
            //        return;
            //    }
            //}
            //// otherwise, check for swapping to the right
            //else
            //{
            //    // get the rectangle of the next element
            //    TabView tabView = Items[SelectedIndex + 1] as TabView;
            //    Rect nxtRect = new Rect();
            //    nxtRect.Location =
            //        tabView.TransformToAncestor(this).Transform(new Point(0, 0));
            //    nxtRect.Size = new Size(tabView.ActualWidth, tabView.ActualHeight);

            //    // find the center of the two elements
            //    double center = (curRect.Left + nxtRect.Right) / 2.0;

            //    // if the mouse is past the center, swap the two elements
            //    if( pos.X > center )
            //    {
            //        int newIndex = SelectedIndex + 1;
            //        object item = Items[SelectedIndex];
            //        Items.RemoveAt(SelectedIndex);
            //        Items.Insert(newIndex, item);
            //        SelectedIndex = newIndex;
            //    }
            //}
        }

        private void ElementDrag_Cancel(object sender, EventArgs e)
        {
            // stop listening for mouse events to reorder or tear off the element
            MouseLeftButtonUp -= new MouseButtonEventHandler(ElementDrag_Cancel);
            MouseMove -= new MouseEventHandler(ElementDrag_Check);
            Mouse.Capture(null);
        }

        private void ElementDrag_TearOff(object sender, EventArgs e)
        {
            //// call the cancel event handler to stop listening for events
            //ElementDrag_Cancel(sender, e);

            //// if there is only one item, tear off the group instead
            //if( Items.Count == 1 )
            //{
            //    // find the desired size and start the tear off
            //    Measure(new Size(double.PositiveInfinity,
            //                     double.PositiveInfinity));
            //    _container.TearOff(this, _offset, DesiredSize);
            //}
            //// otherwise, remove the tab
            //else
            //{
            //    // remove the item and add it to a new tab group
            //    Items.Remove(_element);
            //    TabGroup tabGroup = new TabGroup();
            //    tabGroup.Items.Add(_element);

            //    // find the desired size and start the tear off
            //    tabGroup.Measure(new Size(double.PositiveInfinity,
            //                              double.PositiveInfinity));
            //    _container.TearOff(tabGroup, _offset, tabGroup.DesiredSize);
            //}
        }

        /////////////////////////////////////////////////////////////////////////////
        // Private Functions

        private bool IsMouseInDragArea()
        {
            //bool inside = false;
            //VisualTreeHelper.HitTest(
            //    _dragArea,
            //    test =>
            //    {
            //        if( test == _dragArea ) inside = true;
            //        return HitTestFilterBehavior.Stop;
            //    },
            //    result => HitTestResultBehavior.Stop,
            //    new PointHitTestParameters(Mouse.GetPosition(_dragArea)));
            //return inside;

            return false;
        }

        /////////////////////////////////////////////////////////////////////////////
        // Private Data

        private IDockContainer _container;
        //private IViewElement _element;
        //private Point _offset;

        /////////////////////////////////////////////////////////////////////////////
        // Control

        static TabGroup()
        {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(TabGroup),
                new FrameworkPropertyMetadata(typeof(TabGroup))
                );
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
        }
    }
}